package com.ruoyi.web.core.config;

import cn.hutool.core.util.StrUtil;
import com.ruoyi.common.utils.SseEmitterUtils;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.util.StringUtils;

import java.io.*;
import java.nio.file.*;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.TimeUnit;

@Slf4j
@Data
public class FileMonitorUtil {

    private volatile CyclicBarrier barrier = new CyclicBarrier(2);

    /**
     *
     * @param filePath 文件绝对路径
     * @param msgTemplate 消息模板 或者 空
     * @param fileEndStr 文件内容终止字符串
     * @param sseId 通讯ID
     */
    @Async("asyncExecutor")
    public void monitoringFileModifyAndSendMsg(String filePath, String msgTemplate, String fileEndStr, String sseId)  {

        try {
            File file = new File(filePath);
            File parentDir = file.getParentFile();

            // 确保父目录存在
            if (parentDir != null && !parentDir.exists()) {
                parentDir.mkdirs();
            }
            if (!file.exists()){
                file.createNewFile();
            }
            monitoring(filePath,msgTemplate,fileEndStr,sseId);
        }catch (Exception e) {
            barrier.reset();
            e.printStackTrace();
            log.error("监听文件异常, 文件:{}, 异常:{}",filePath,e.getMessage());
        }finally {

        }
    }



    private void monitoring(String filePath, String msgTemplate, String fileEndStr ,String sseId) throws Exception {
        // 创建一个文件系统监听器
        WatchService watchService = FileSystems.getDefault().newWatchService();
        // 获取文件所在的目录路径
        Path dir = Paths.get(filePath).getParent();
        // 注册监听器来监听文件变化
        dir.register(watchService, StandardWatchEventKinds.ENTRY_MODIFY);
        log.info("Watching file for changes: {}",filePath);
        await();
        // 记录文件当前的长度
        long lastPosition = 0;

        //开始监听文件修改的内容
        A: while  (true) {
            WatchKey key = null;
            try {
                //超过10分钟 自动停止
                key = watchService.poll(10, TimeUnit.MINUTES);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (null == key) {
                log.info("monitoring 超时后自动跳出, filePath: {}",filePath);
                break;
            }

            for (WatchEvent<?> event : key.pollEvents()) {
                WatchEvent.Kind<?> kind = event.kind();

                // 确保是文件修改事件
                if (kind == StandardWatchEventKinds.ENTRY_MODIFY) {
                    Path modifiedFilePath = (Path) event.context();
                    if (modifiedFilePath.endsWith(Paths.get(filePath).getFileName())) {
                        // 打开文件并定位到上次记录的位置 暂停一会儿,让写操作写完
                        log.debug("检测到修改");
                        Thread.sleep(1000);
                        try (RandomAccessFile file = new RandomAccessFile(filePath, "r")) {
                            file.seek(lastPosition);

                            try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file.getFD()), "GBK"))) {
                                String line;
                                while ((line = reader.readLine()) != null) {
                                    // 在这里可以对读取到的内容进行处理
                                    if (StringUtils.hasLength(line)) {
                                        if (fileEndStr.equals(line.trim())) {
                                            //监测到终止
                                            log.info("monitor 监测到终止 filePath: {}",filePath);
                                            break A;
                                        }
                                        if (StrUtil.isBlank(msgTemplate)){
                                            SseEmitterUtils.sendMessage(sseId,line);
                                        }else {
                                            SseEmitterUtils.sendMessage(sseId,msgTemplate.replace("PLACEHOLDER", line));
                                        }
                                    }
                                }
                                // 更新记录的位置为文件的当前长度
                                lastPosition = file.getFilePointer();
                            }
                        } catch (IOException ex) {
                            ex.printStackTrace();
                        }
                    }
                }
            }

            // 重置监听键，准备下一次监听
            boolean valid = key.reset();
            if (!valid) {
                break;
            }
        }
        log.info("文件监听结束:{}",filePath);
    }

    public void await(){
        try {
            this.barrier.await(5,TimeUnit.SECONDS);
        }catch (Exception e){
            e.printStackTrace();
            reset();
        }
    }

    public void reset(){
        this.barrier.reset();
    }


}
